#ifndef DATATIME_H
#define DATATIME_H
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <ctime>
#include <functional>
#include <iomanip>
#include <iostream>
#include <memory>
#include <mutex>
#include <sstream>
class DateTime
{
public:
    DateTime(); /// The current dateTime.
    ~DateTime();
    DateTime(int year, int month, int day, int hour = 0, int minute = 0, int second = 0, int millisecond = 0, int microsecond = 0);

    DateTime(const DateTime &other);
    DateTime &operator=(const DateTime &other);

    int64_t millisecondsSinceEpoch() const;
    int64_t secondsSinceEpoch() const;

    int year() const; /// Returns the year. 2024
    int month() const; /// Returns 1~12
    int week(int firstDayOfWeek = 1) const; /// Returns the week number within the year

    int day() const; /// Returns 1~31
    int dayOfWeek() const; /// Returns the weekday (0 to 6, 0 = Sunday, 1 = Monday, ..., 6 = Saturday).
    int dayOfYear() const; /// Rrturns 1~365

    int hour() const; // 0~23
    int hourAMPM() const; // 0~12

    bool isAM() const; // hour < 12;
    bool isPM() const; /// hour >= 12

    int minute() const; /// Returns 0~59
    int second() const; /// Returns 0~59

    int millisecond() const; /// Returns 0~999
    int microsecond() const; /// Returns 0~999

    /*
     * format
     * y:year               yy/yyyy     24/2024
     * M:Month              M/MM        1/01
     * d:day                d/dd        1/01
     * m:Minut              m/mm        0/00
     * s:Second             s/ss        1/01
     * z:Millisecond        z/zz/zzz    9/99/999
     * a:display am or pm;  a/ap
     * A:display AM or PM;  A/AP
     *
     * yyyy-MM-dd hh:mm:ss.zzz a A
     * 2023-08-25 10:05:05.151 am AM
     *
     * yy-M-d h:m:s.zzz
     * 23-8-25 10:5:5.151
     */

    std::string toString(const std::string &format = "yyyy-MM-dd hh:mm:ss") const; // yyyy-MM-dd hh:mm:ss

    static int64_t currentMicrosecondsSinceEpoch();
    static int64_t currentMillisecondsSince();
    static int64_t currentSecondsSinceEpoch();
    static DateTime fromMilliSecondsSinceEpoch(int64_t msecs);
    static DateTime fromSecondsSinceEpoch(int64_t secs);

private:
    void update();

private:
    int64_t ts_; // Microseconds since epoch
    struct tm tm_;
};

#endif